﻿package main
{
	import away3d.cameras.Camera3D;
	import away3d.containers.ObjectContainer3D;
	import away3d.core.base.Object3D;
	import away3d.core.math.Matrix3D;
	import away3d.core.math.Number3D;
	import away3d.events.LoaderEvent;
	import away3d.loaders.Collada;
	import away3d.loaders.Object3DLoader;
	import away3d.loaders.data.MaterialData;
	import away3d.materials.BitmapMaterial;
	
	import com.baseoneonline.flash.utils.logger.Logger;
	
	import flash.display.Sprite;
	import flash.events.Event;
	
	import main.util.Util;
	
	
	[Event(type="flash.events.Event", name="complete")]
	public class SceneBuilder extends Sprite
	{
		
		private var sceneObject:ObjectContainer3D;
		private var cameras:Object;
		
		public var bitmapPrecision:int = 0;
		
		public function SceneBuilder() {
		}
		

		
		public function getSceneObject():Object3D {
			return sceneObject;
		}
		
		public function getCamera(id:String):Camera3D {
			var cam:Camera3D = cameras[id];
			if (!cam) throw new Error("Camera not found: "+id);
			return cam;
		}
		
		public function getCameras():Array {
			var a:Array = [];
			for each(var cam:Camera3D in cameras) {
				a.push(cam);
			}
			return a;
		}
		
		public function initialize(sceneXML:XML):void {
			if (sceneXML == null) throw new Error("Cannot be null!");
			
			sceneObject = Collada.parse(sceneXML);
			var ldr:Object3DLoader = sceneObject as Object3DLoader;
			ldr.texturePath = "textures";
		//	ldr.addOnSceneChange(handler);
			ldr.addOnSuccess(onSceneComplete);
			ldr.addOnError(onSceneError);
			cameras = extractCameras(sceneXML);
		}
		
		private function onSceneError(e:LoaderEvent):void {
			throw new Error("Error processing scene");
		}
		
		private function onSceneComplete(e:Event):void {

			fixMaterials();
			dispatchEvent(new Event(Event.COMPLETE));
		}
		
		private function fixMaterials():void {
			for each(var mat:MaterialData in sceneObject.materialLibrary) {
				if (mat.material && mat.material is BitmapMaterial) {
					var bmp:BitmapMaterial = mat.material as BitmapMaterial;
					//bmp.smooth = true;
					//bmp.precision = 5;
					bmp.precision = bitmapPrecision;
					bmp.repeat = true;
				}
			}
		}
		
		private function extractCameras(xml:XML):Object {
			Logger.debug(this, "Extracting cameras");
			var o:Object = {};
			var i:int=0;
			for each(var x:XML in xml..instance_camera) {
				// Find the camera shape
				var xCamInst:XML = x.parent();
				var xCam:XML = findCamera(xml, String(Util.exists(xCamInst.instance_camera.@url)).substr(1));
				var xCamAim:XML = findCameraAim(xCamInst);
								
				// Camera found!
				var cam:Camera3D = new Camera3D();
				cam.name = Util.exists(xCamInst.@id);
				Logger.debug(this, "Camera found: "+ cam.name);
				
				// Place camera.
				var camMatrix:Array = Util.exists(xCamInst.matrix.text()).split(" ");
				cam.transform.array2matrix(camMatrix, true, 100);
				
				// Aim camera
				var aimMatrix:Array = Util.exists(xCamAim.matrix.text()).split(" ");
				var matr:Matrix3D = new Matrix3D();
				matr.array2matrix(aimMatrix, true, 100);
				cam.lookAt(new Number3D(matr.position.x, matr.position.y, matr.position.z), Number3D.UP);
				
				// Set fov
				cam.focus = 5;
				var fov:Number = Util.exists(xCam.optics.technique_common.perspective.xfov);
				var tan:Number = Math.tan((fov/2) * (Math.PI/180));
				var w:Number = 640; 
				cam.zoom = w/(2*tan*cam.focus);
	
				o[cam.name] = cam;
				i++;
			}
			Logger.debug(this, "Cameras found: "+i);
			return o;
		}
		
	
		private function findCamera(xml:XML, id:String):XML {
			for each(var x:XML in xml..camera) {
				if (x.@id == id) return x;
			}
			throw new Error("Could not find camera with id: "+id);
			return null;
		}
		
		private function findCameraAim(xCamInst:XML):XML {
			var prt:XML = xCamInst.parent();
			for each(var x:XML in prt.node) {
				if (x.@id == xCamInst.@id+"_aim") {
					return x;
				}
			}
			throw new Error("Camera aim not found for camera: "+xCamInst.@id);
			return null;
		}

	}
}